/*
  protocol.c - controls grblHAL execution protocol and procedures

  Part of grblHAL

  Copyright (c) 2017-2024 Terje Io
  Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
  Copyright (c) 2009-2011 Simen Svale Skogsrud

  grblHAL is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  grblHAL is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <string.h>

#include "hal.h"
#include "nuts_bolts.h"
#include "nvs_buffer.h"
#include "override.h"
#include "state_machine.h"
#include "motion_control.h"
#include "sleep.h"
#include "protocol.h"
#include "machine_limits.h"

#ifndef RT_QUEUE_SIZE
// 允许同时存在的RT函数的数量,这些注册进来的函数只会执行一遍,运行完就会释放空间,这是个环形缓冲区
#define RT_QUEUE_SIZE 16 // must be a power of 2
#endif

// Define line flags. Includes comment type tracking and line overflow detection.
typedef union {
    uint8_t value;
    struct {
        uint8_t overflow            :1,//指令+注释太长,发生了覆盖,这个标志位备这是为1
                comment_parentheses :1,
                comment_semicolon   :1,
                unassigned          :5;
    };
} line_flags_t;

typedef struct {
    void *data;
    fg_task_ptr task;
} delayed_task_t;

typedef struct {
    volatile uint_fast8_t head;
    volatile uint_fast8_t tail;
    delayed_task_t task[RT_QUEUE_SIZE];
} realtime_queue_t;

static uint_fast16_t char_counter = 0;//指令长度计数器 比如控制台输入"G1 X100 F1000"char_counter = 13
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
static char xcommand[LINE_BUFFER_SIZE]; // 跟 protocol_enqueue_gcode 有关 这里面的指令会在 bool protocol_main_loop (void) 中执行
static bool keep_rt_commands = false;// 标记RT指令 $xxx
static realtime_queue_t realtime_queue = {0};
static on_execute_realtime_ptr on_execute_delay;

static void protocol_execute_rt_commands (sys_state_t state);
static void protocol_exec_rt_suspend (sys_state_t state);

// 将不通过常规输入流发起的 GCode 命令加入队列
// 该函数的作用是将传入的 GCode 命令添加到系统的队列中执行，
// 但它会检查当前系统状态和命令的有效性，确保命令可以被正确处理。
// 如果命令有效，它会将 GCode 字符串复制到 xcommand 中，以便后续处理。
bool protocol_enqueue_gcode (char *gcode)
{
    // 初步检查命令是否有效
    // 1. 确保 xcommand 空（即没有未完成的命令）
    // 2. 系统处于空闲状态（STATE_IDLE）或处于报警状态、手动操作、工具更换等允许执行特殊命令的状态
    // 3. 确保当前没有处于运动取消状态
    bool ok = xcommand[0] == '\0' &&                                     // 确保没有未完成的命令
               (state_get() == STATE_IDLE || (state_get() & (STATE_ALARM|STATE_JOG|STATE_TOOL_CHANGE))) && // 检查当前系统状态
                 bit_isfalse(sys.rt_exec_state, EXEC_MOTION_CANCEL);    // 确保没有处于运动取消状态

    // 如果 gc_state.file_run 为真（表示文件正在运行），则进一步检查：
    // 1. 确保程序流不是正在运行（ProgramFlow_Running）
    // 2. 或者 GCode 命令是 $J=（手动控制命令），这种命令可以跳过程序流检查
    if(ok && gc_state.file_run)
        ok = gc_state.modal.program_flow != ProgramFlow_Running || strncmp((char *)gcode, "$J=", 3);

    // 如果命令有效，复制 GCode 到 xcommand 缓冲区
    if(ok)
        strcpy(xcommand, gcode);

    // 返回命令是否成功加入队列的状态
    return ok;
}

static void protocol_on_execute_delay (sys_state_t state)
{
    if(sys.rt_exec_state & EXEC_RT_COMMAND) {
        system_clear_exec_state_flag(EXEC_RT_COMMAND);
        protocol_execute_rt_commands(0);
    }

    on_execute_delay(state);
}

static bool recheck_line (char *line, line_flags_t *flags)
{
    bool keep_rt_commands = false, first_char = true;

    // 初始化 flags 的值为 0
    flags->value = 0;

    // 确保行不是空的，开始逐字符检查
    if(*line != '\0') do {

        switch(*line) {  // 根据当前字符进行处理

            case '$': // 检查是否为实时命令（实时命令以 $ 开头）
            case '[': // 同样，'[' 也是表示某些实时命令的开始
                if(first_char)  // 如果是行的第一个字符
                    keep_rt_commands = true;  // 设置标记为 true，表示接下来的字符是实时命令
                break;

            case '(': // 开始注释的符号
                // 如果没有正在处理实时命令且没有遇到分号注释，开启注释处理
                if(!keep_rt_commands && (flags->comment_parentheses = !flags->comment_semicolon)) {
                    // 设置标志，表示进入了括号注释模式
                    keep_rt_commands = !hal.driver_cap.no_gcode_message_handling; 
                    // 如果硬件不支持 G-code 消息处理，则停止实时命令处理
                }
                break;

            case ')': // 注释结束符
                if(!flags->comment_semicolon)
                    flags->comment_parentheses = keep_rt_commands = false;  // 结束括号注释模式
                break;

            case ';': // 分号表示 G-code 注释（后续的内容是注释）
                if(!flags->comment_parentheses) { // 如果不是括号注释
                    keep_rt_commands = false;  // 停止处理实时命令
                    flags->comment_semicolon = On;  // 设置分号注释标志
                }
                break;
        }

        first_char = false;  // 标记已处理过第一个字符

    } while(*++line != '\0');  // 一直处理直到行结束

    // 返回是否保持实时命令的标志
    return keep_rt_commands;
}


/*
  GRBL PRIMARY LOOP:
  这个是GRBL的主循环
  sys.abort为1会退出这个函数
*/
bool protocol_main_loop (void)
{
    // 前面这一堆都是在检测警告状态
    if(sys.alarm == Alarm_SelftestFailed) {
        sys.alarm = Alarm_None;
        system_raise_alarm(Alarm_SelftestFailed);
    } else if (hal.control.get_state().e_stop) {
        // Check for e-stop active. Blocks everything until cleared.
        system_raise_alarm(Alarm_EStop);
        grbl.report.feedback_message(Message_EStop);
    } else if(hal.control.get_state().motor_fault) {
        // Check for motor fault active. Blocks everything until cleared.
        system_raise_alarm(Alarm_MotorFault);
        grbl.report.feedback_message(Message_MotorFault);
    } else if(settings.probe.enable_protection && hal.control.get_state().probe_triggered) {
        system_raise_alarm(Alarm_ProbeProtect);
        grbl.report.feedback_message(Message_ProbeProtected);
    } else if (limits_homing_required()) {
        // Check for power-up and set system alarm if homing is enabled to force homing cycle
        // by setting grblHAL's alarm state. Alarm locks out all g-code commands, including the
        // startup scripts, but allows access to settings and internal commands.
        // Only a successful homing cycle '$H' will disable the alarm.
        // NOTE: The startup script will run after successful completion of the homing cycle. Prevents motion startup
        // blocks from crashing into things uncontrollably. Very bad.
        system_raise_alarm(Alarm_HomingRequired);
        grbl.report.feedback_message(Message_HomingCycleRequired);
    } else if (settings.limits.flags.hard_enabled &&
                settings.limits.flags.check_at_init &&
                 (limit_signals_merge(hal.limits.get_state()).value & sys.hard_limits.mask)) {
        if(sys.alarm == Alarm_LimitsEngaged && hal.control.get_state().limits_override)
            state_set(STATE_IDLE); // Clear alarm state to enable limit switch pulloff.
        else {
            // Check that no limit switches are engaged to make sure everything is good to go.
            system_raise_alarm(Alarm_LimitsEngaged);
            grbl.report.feedback_message(Message_CheckLimits);
        }
    } else if(sys.cold_start && (settings.flags.force_initialization_alarm || hal.control.get_state().reset)) {
        state_set(STATE_ALARM); // Ensure alarm state is set.
        grbl.report.feedback_message(Message_AlarmLock);
    } else if (state_get() & (STATE_ALARM|STATE_SLEEP)) {
        // Check for and report alarm state after a reset, error, or an initial power up.
        // NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed.
        // Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges.
        if(sys.alarm == Alarm_HomingRequired)
            sys.alarm = Alarm_None; // Clear Alarm_HomingRequired as the lock has been overridden by a soft reset.
        state_set(STATE_ALARM); // Ensure alarm state is set.
        grbl.report.feedback_message(Message_AlarmLock);
    } else {
        state_set(STATE_IDLE);
#ifndef NO_SAFETY_DOOR_SUPPORT
        // Check if the safety door is open.
        // settings.safety_door.flags.ignore_when_idle 是 $61
        if (hal.signals_cap.safety_door_ajar && !settings.safety_door.flags.ignore_when_idle && hal.control.get_state().safety_door_ajar) {
            system_set_exec_state_flag(EXEC_SAFETY_DOOR);
            protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state.
        }
#endif
        // All systems go!
        system_execute_startup(); // Execute startup script.
    }

    // Ensure spindle and coolant is switched off on a cold start
    // 开机的时候 sys.cold_start = 1
    if(sys.cold_start) {
        spindle_all_off();
        hal.coolant.set_state((coolant_state_t){0});
        if(realtime_queue.head != realtime_queue.tail)
            system_set_exec_state_flag(EXEC_RT_COMMAND);  // execute any boot up commands
        on_execute_delay = grbl.on_execute_delay;
        grbl.on_execute_delay = protocol_on_execute_delay;
        sys.cold_start = false;
    } else // TODO: if flushing entries from the queue that has allocated data associated then these will be orphaned/leaked.
        memset(&realtime_queue, 0, sizeof(realtime_queue_t));

    // ---------------------------------------------------------------------------------
    // Primary loop! Upon a system abort, this exits back to main() to reset the system.
    // This is also where grblHAL idles while waiting for something to do.
    // ---------------------------------------------------------------------------------

    int16_t c;
    char eol = '\0';
    line_flags_t line_flags = {0};

    xcommand[0] = '\0';
    char_counter = 0;
    keep_rt_commands = false;

    while(true) {

        // Process one line of incoming stream data, as the data becomes available. Performs an
        // initial filtering by removing leading spaces and control characters.
        // 从串口环形缓冲区中读取一个字节
        while((c = hal.stream.read()) != SERIAL_NO_DATA) {

            if(c == ASCII_CAN) {
                eol = xcommand[0] = '\0';
                keep_rt_commands = false;
                char_counter = line_flags.value = 0;
                gc_state.last_error = Status_OK;
                if (state_get() == STATE_JOG) // Block all other states from invoking motion cancel.
                    system_set_exec_state_flag(EXEC_MOTION_CANCEL);
            } else if(c == ASCII_EOF) {
                if(grbl.on_file_end)
                    grbl.on_file_end(hal.stream.file, gc_state.last_error);
            } else if ((c == '\n') || (c == '\r')) { // End of line reached
                // 从这里可以看出,Gcode指令以 "\r\n" 结尾,任意一个就行,而且结尾字符不会复制到 line 中会被替换为 '\0' 作为字符串的结尾
                // Check for possible secondary end of line character, do not process as empty line
                // if part of crlf (or lfcr pair) as this produces a possibly unwanted double response
                if(char_counter == 0 && eol && eol != c) {
                    eol = '\0';
                    continue;
                } else
                    eol = (char)c;               // eol中存放的是字符串结尾符号

                if(!protocol_execute_realtime()) // Runtime command check point.
                    return !sys.flags.exit;      // Bail to calling function upon system abort
                
                // 给指令加上字符串结尾字符
                line[char_counter] = '\0'; // Set string termination character.
              #if REPORT_ECHO_LINE_RECEIVED
                report_echo_line_received(line);
              #endif
                // 到这里 控制台输入 "G1 X100 F1000\r\n" 的时候 line中存放的字符串是 "G1 X100 F1000\0" 结尾字符串是丢弃的
                // Direct and execute one line of formatted input, and report status of execution.
                // 下面是检查指令的格式
                if (line_flags.overflow) // Report line overflow error.         // 指令的长度超过了最大限制
                    gc_state.last_error = Status_Overflow;                      // 标记错误
                else if(*line == '\0') // Empty line. For syncing purposes.     // 空指令
                    gc_state.last_error = Status_OK;                            // 允许空指令
                else if(*line == '$') {// grblHAL '$' system command            // 以 $ 开头的指令特殊处理
                    if((gc_state.last_error = system_execute_line(line)) == Status_LimitsEngaged) {
                        system_raise_alarm(Alarm_LimitsEngaged);
                        grbl.report.feedback_message(Message_CheckLimits);
                    }
                } else if(*line == '[' && grbl.on_user_command)
                    gc_state.last_error = grbl.on_user_command(line);
                else if ( state_get() & (STATE_ALARM|STATE_ESTOP|STATE_JOG) ) // Everything else is gcode. Block if in alarm, eStop or jog mode.
                    gc_state.last_error = Status_SystemGClock;                // 系统处于 STATE_ALARM|STATE_ESTOP|STATE_JOG 中的任意一个状态都标记为 Status_SystemGClock
#if COMPATIBILITY_LEVEL == 0
                else if(gc_state.last_error == Status_OK || gc_state.last_error == Status_GcodeToolChangePending) { // Parse and execute g-code block.
#else
                else { // Parse and execute g-code block.

#endif
                    if((gc_state.last_error = gc_execute_block(line)) != Status_OK)
                        eol = '\0';
                }

                // Add a short delay for each block processed in Check Mode to
                // avoid overwhelming the sender with fast reply messages.
                // This is likely to happen when streaming is done via a protocol where
                // the speed is not limited to 115200 baud. An example is native USB streaming.
#if CHECK_MODE_DELAY
                if(state_get() == STATE_CHECK_MODE)
                    hal.delay_ms(CHECK_MODE_DELAY, NULL);
#endif
                if(ABORTED)
                    break;
                else // 这里需要关注
                    grbl.report.status_message(gc_state.last_error); // 这里会上报信息,也是上报 'ok' 的地方; 如果屏蔽掉,就不会再有发一条Gcode就返回一条'ok'的机制了
                // Reset tracking data for next line.
                keep_rt_commands = false;
                char_counter = line_flags.value = 0;

            } else if (c != ASCII_BS && c <= (char_counter > 0 ? ' ' - 1 : ' '))
                continue; // Strip control characters and leading whitespace.
            else { // 这里才是提取完整的命令
                switch(c) {// 根据字符 c 的不同值执行不同的操作

                    case '$': // '$' 代表一个特殊的实时命令（如GRBL的设置命令）
                    case '[': // '[' 也是一种特殊的命令开始标志 ; 这个特殊指令需要初始化 grbl.on_user_command 通过这个函数去处理,默认不支持
                        if (char_counter == 0)  // 如果当前指令的长度为0（即这是指令的开始）
                            keep_rt_commands = true; // 启动实时命令的处理标志，保持后续实时命令的处理
                        break;

                    case '(':   // '(' 开始的注释部分（此处可能表示多行注释的开始）
                                // 如果当前没有实时命令，并且还没有遇到注释标记
                        if (!keep_rt_commands && (line_flags.comment_parentheses = !line_flags.comment_semicolon))
                                // 记录注释开始，标志置为true，表示接下来的字符是注释内容
                            keep_rt_commands = !hal.driver_cap.no_gcode_message_handling; 
                                // 此标志控制是否暂停对可打印命令字符的实时处理
                        break;

                    case ')':   // ')' 注释结束
                        if (!line_flags.comment_semicolon)
                                // 如果不是分号注释，标记注释结束，停止处理实时命令
                            line_flags.comment_parentheses = keep_rt_commands = false;
                        break;

                    case ';':   // ';' 也是注释符号，标志一行注释结束
                        if (!line_flags.comment_parentheses) {
                                // 如果当前没有是括号中的注释内容
                            keep_rt_commands = false;           // 停止实时命令处理
                            line_flags.comment_semicolon = On;  // 启用分号注释标志
                        }
                        break;

                    case ASCII_BS:      // ASCII 控制字符 BS（退格符），表示删除字符
                    case ASCII_DEL:     // ASCII 删除符 DEL，表示删除当前字符
                        if (char_counter) { 
                            // 如果当前缓冲区不为空，则删除最后一个字符
                            line[--char_counter] = '\0'; // 将字符计数器减1并清空最后一个字符
                            // 删除一个字符后检查命令有效性
                            keep_rt_commands = recheck_line(line, &line_flags); 
                            // 重新检查当前行是否符合有效命令
                        }
                        continue; // 继续下一轮循环，跳过当前字符的处理

                }

                // 如果当前行字符数没有溢出（即没有达到最大字符数）
                if (!(line_flags.overflow = char_counter >= (LINE_BUFFER_SIZE - 1)))
                    // 将字符 c 存储到 line 数组中，并增加字符计数器
                    line[char_counter++] = c;
            }
        }

        // 串口的缓存区中读不到任何数据后,会运行到这里
        // Handle extra command (internal stream)
        if(xcommand[0] != '\0') {
            if (xcommand[0] == '$')                 // grblHAL '$' system command
                system_execute_line(xcommand);
            else if (state_get() & (STATE_ALARM|STATE_ESTOP|STATE_JOG)) // Everything else is gcode. Block if in alarm, eStop or jog state.
                grbl.report.status_message(Status_SystemGClock);
            else // Parse and execute g-code block.
                gc_execute_block(xcommand);

            xcommand[0] = '\0';
        }

        // If there are no more characters in the input stream buffer to be processed and executed,
        // this indicates that g-code streaming has either filled the planner buffer or has
        // completed. In either case, auto-cycle start, if enabled, any queued moves.
        protocol_auto_cycle_start();

        if(!protocol_execute_realtime() && sys.abort) // Runtime command check point.
            return !sys.flags.exit;                   // Bail to main() program loop to reset system.

        sys.cancel = false;

        // Check for sleep conditions and execute auto-park, if timeout duration elapses.
        // settings.flags.sleep_enable = $62 void sleep_check (void)
        if(settings.flags.sleep_enable)
            sleep_check();
    }
}


// Block until all buffered steps are executed or in a cycle state. Works with feed hold
// during a synchronize call, if it should happen. Also, waits for clean cycle end.
// 带有阻塞功能,直到 block_buffer_head 清空 
bool protocol_buffer_synchronize (void)
{
    bool ok = true;

    // If system is queued, ensure cycle resumes if the auto start flag is present.
    protocol_auto_cycle_start();

    sys.flags.synchronizing = On;
    // 这里有个死循环;会保证实时指令的响应,等待系统状态的改变和运动控制块运行完
    // block_buffer_head 中的块被清空 并且系统的状态不再是 STATE_CYCLE
    while ((ok = protocol_execute_realtime()) && (plan_get_current_block() || state_get() == STATE_CYCLE));
    sys.flags.synchronizing = Off;

    return ok;
}


// Auto-cycle start triggers when there is a motion ready to execute and if the main program is not
// actively parsing commands.
// NOTE: This function is called from the main loop, buffer sync, and mc_line() only and executes
// when one of these conditions exist respectively: There are no more blocks sent (i.e. streaming
// is finished, single commands), a command that needs to wait for the motions in the buffer to
// execute calls a buffer sync, or the planner buffer is full and ready to go.
void protocol_auto_cycle_start (void)
{
    // block_buffer 中有数据就把 sys.rt_exec_state 的 EXEC_CYCLE_START 位设置为 1
    // plan_get_current_block的作用是 block_buffer_head这个链表有数据就不会返回 NULLm,链表中没有任何数据的时候返回 NULL
    if (plan_get_current_block() != NULL) // Check if there are any blocks in the buffer.
        system_set_exec_state_flag(EXEC_CYCLE_START); // If so, execute them!
}


// This function is the general interface to grblHAL's real-time command execution system. It is called
// from various check points in the main program, primarily where there may be a while loop waiting
// for a buffer to clear space or any point where the execution time from the last check point may
// be more than a fraction of a second. This is a way to execute realtime commands asynchronously
// (aka multitasking) with grbl's g-code parsing and planning functions. This function also serves
// as an interface for the interrupts to set the system realtime flags, where only the main program
// handles them, removing the need to define more computationally-expensive volatile variables. This
// also provides a controlled way to execute certain tasks without having two or more instances of
// the same task, such as the planner recalculating the buffer upon a feedhold or overrides.
// NOTE: The sys_rt_exec_state variable flags are set by any process, step or input stream events, pinouts,
// limit switches, or the main program.
// Returns false if aborted
// 这个函数只要是处理挂起状态(SLEEP)下的实时状态响应和警告,实时转态等突发信号的处理
// 在里面会完成 state_get() = sys_state = rt_exec = sys.rt_exec_state
// 需要终止系统返回0 系统可以正常运行返回1
// 从运动控制块中读取速度和轨迹信息,在这里会调用 protocol_exec_rt_system--->st_prep_buffer - 这里读取运动控制块并做加减速规划
bool protocol_execute_realtime (void)
{
    if( protocol_exec_rt_system() ) {// 执行完快速响应信号后没发现需要终止系统运行

        sys_state_t state = state_get();
        if(sys.suspend) // 挂起标志位
            // 处理 STATE_SLEEP 状态,检测安全门,主轴的覆盖,并调用 protocol_exec_rt_system
            protocol_exec_rt_suspend(state);

#if NVSDATA_BUFFER_ENABLE
        // settings_dirty.is_dirty : 如果不为0则表示有改变设置的动作,需要更新NVS区
        // gc_state.file_run 的状态是控制台收到%指令后改变的;这个条件先跳过
        if((state == STATE_IDLE || (state & (STATE_ALARM|STATE_ESTOP))) && settings_dirty.is_dirty && !gc_state.file_run)
            nvs_buffer_sync_physical();
#endif
    }
    return !ABORTED;
}

// 这个函数的作用是读取控制台输入的指令字符,提取一条完整的指令并存储到 line[]中 char_counter 记录着指令的长度
static void protocol_poll_cmd (void)
{
    int16_t c;

    if ((c = hal.stream.read()) != SERIAL_NO_DATA) {    // 如果串口有数据反馈
        if ((c == '\n') || (c == '\r')) {               // 如果接收到换行符（\n）或回车符（\r），表示一条指令的结束
            line[char_counter] = '\0';                  // 在指令的末尾加上字符串结束字符（\0），表示指令字符串的结束
                                                        // 判断指令是否为空或是配置命令，并执行相应的操作
            gc_state.last_error = *line == '\0' ? Status_OK :
                                  (*line == '$' ? system_execute_line(line) : Status_SystemGClock);
            char_counter = 0;   // 重置字符计数器
            *line = '\0';       // 清空缓冲区，准备接收下一条指令
                                // 根据执行结果报告状态信息
            grbl.report.status_message(gc_state.last_error);    // 报告错误信息或执行结果
        } else if (c == ASCII_DEL || c == ASCII_BS) {           // 如果收到删除符（DEL）或退格符（BS）
            if (char_counter)                                   // 如果缓冲区已有字符
                line[--char_counter] = '\0';                    // 删除最后一个字符
        } else if (char_counter == 0 ? c != ' ' : char_counter < (LINE_BUFFER_SIZE - 1)) {  
                                                                // 如果字符计数器为 0，且字符不是空格，或者字符计数器没有超出缓冲区限制
            line[char_counter++] = c;                           // 将字符存储到缓冲区并增加计数器
        }

        // 监控实时命令（以 $ 开头的命令），用于决定是否继续保持对实时命令的处理
        // 启用了 $39后 对实时指令的字符拓展
        keep_rt_commands = char_counter > 0 && *line == '$';
    }
}

// Executes run-time commands, when required. This function primarily operates as grblHAL's state
// machine and controls the various real-time features grblHAL has to offer.
// NOTE: Do not alter this unless you know exactly what you are doing!
// 实时状态更改;警告状态;给进速度覆盖;主轴速度覆盖;冷却剂开关状态覆盖以及 st_prep_buffer 的快速反应
// sys.rt_exec_state 和 sys.rt_exec_alarm 两个标志位标记的状态对应的快速响应逻辑在这里实现
// 返回值为1 表示不终止 为0 表示终止
bool protocol_exec_rt_system (void)
{
    rt_exec_t rt_exec;
    bool killed = false;

    // sys.rt_exec_alarm 这个标志位通过 system_set_exec_alarm 设置;system_set_exec_alarm跟限位强相关
    // 如果存在警告标志位
    // system_clear_exec_alarm() 清零 sys.rt_exec_alarm 并返回 sys.rt_exec_alarm 清零之前的值
    if (sys.rt_exec_alarm && (rt_exec = system_clear_exec_alarm())) { // Enter only if any bit flag is true
        // 实时状态管理,在stepper.c中被更改
        if((sys.reset_pending = !!(sys.rt_exec_state & EXEC_RESET))) {
            // Kill spindle and coolant.
            killed = true;
            spindle_all_off(); // 关闭全部的主轴
            hal.coolant.set_state((coolant_state_t){0});// 关闭冷却剂
        }

        // System alarm. Everything has shutdown by something that has gone severely wrong. Report
        // the source of the error to the user. If critical, grblHAL disables by entering an infinite
        // loop until system reset/abort.
        // 突发的实时警告同步为系统警告,并变更系统的状态
        // 这里先不关注这些信号的来源
        system_raise_alarm((alarm_code_t)rt_exec);

        // sys.rt_exec_state & EXEC_RESET 的条件成立,需要通知插件或者外设复位
        if(killed) // Tell driver/plugins about reset.
            hal.driver_reset();

        // Halt everything upon a critical event flag. Currently hard and soft limits flag this.
        if((sys.blocking_event = (alarm_code_t)rt_exec == Alarm_HardLimit ||
                                  (alarm_code_t)rt_exec == Alarm_SoftLimit ||
                                   (alarm_code_t)rt_exec == Alarm_EStop ||
                                    (alarm_code_t)rt_exec == Alarm_MotorFault)) {

            system_set_exec_alarm(rt_exec);//(rt_exec = system_clear_exec_alarm())清除了 sys.rt_exec_alarm 这里恢复回来

            switch((alarm_code_t)rt_exec) { // 报告状态到控制台;只对急停和电机状态区分,其他都报告 Message_CriticalEvent (1)

                case Alarm_EStop:
                    grbl.report.feedback_message(Message_EStop);
                    break;

                case Alarm_MotorFault:
                    grbl.report.feedback_message(Message_MotorFault);
                    break;

                default:
                    grbl.report.feedback_message(Message_CriticalEvent);
                    break;
            }

            // 清除 sys.rt_exec_state 中的 EXEC_RESET 标志
            system_clear_exec_state_flag(EXEC_RESET); // Disable any existing reset

            *line = '\0';                               // 清除指令行的字符串
            char_counter = 0;                           // 这里无法确定这个变量的作用
            hal.stream.reset_read_buffer();             // 串口环形缓存区链表复位

            // sys.rt_exec_state 的 EXEC_RESET 位如果是0
            // 退出机制暂时还不清楚
            while (bit_isfalse(sys.rt_exec_state, EXEC_RESET)) {

                // Block everything, except reset and status reports, until user issues reset or power
                // cycles. Hard limits typically occur while unattended or not paying attention. Gives
                // the user and a GUI time to do what is needed before resetting, like killing the
                // incoming stream. The same could be said about soft limits. While the position is not
                // lost, continued streaming could cause a serious crash if by chance it gets executed.
                
                if(bit_istrue(sys.rt_exec_state, EXEC_STATUS_REPORT)) {
                    system_clear_exec_state_flag(EXEC_STATUS_REPORT);
                    report_realtime_status();   // 这里报告 ? 指令需要反馈的内容
                }

                protocol_poll_cmd();            // 从控制台读取一个字符
                grbl.on_execute_realtime(STATE_ESTOP);// 实时指令钩子,这里最好判断一下指针是不是为空
            }
            // 清理掉警告标志
            system_clear_exec_alarm(); // Clear alarm
        }
    }

    // system_set_exec_state_flag(EXEC_XXX) 设置 sys.rt_exec_state
    // rt_exec = system_clear_exec_states() 读取 sys.rt_exec_state 状态到 rt_exec 这个操作会清除 sys.rt_exec_state
    if (sys.rt_exec_state && (rt_exec = system_clear_exec_states())) { // Get and clear volatile sys.rt_exec_state atomically.

        // Execute system abort.
        if((sys.reset_pending = !!(rt_exec & EXEC_RESET))) {
            if(!killed) {// 只要 sys.rt_exec_alarm 不为0  killed 就为1
                // Kill spindle and coolant.
                spindle_all_off();// 关闭主轴和冷却液
                hal.coolant.set_state((coolant_state_t){0});
            }
            // Only place sys.abort is set true, when E-stop is not asserted.
            // hal.control.get_state() 会通过 $14 改变信号的方向,会反馈有安全门,探针,急停等信号的状态
            if(!(sys.abort = !hal.control.get_state().e_stop)) {// 处理急停 NOTE:这个地方的逻辑还有点没明白
                hal.stream.reset_read_buffer();                 // 串口环形缓存区链表复位
                system_raise_alarm(Alarm_EStop);                // 系统的状态设置为 Alarm_EStop
                grbl.report.feedback_message(Message_EStop);    // 报告急停状态到控制台
            } else if(hal.control.get_state().motor_fault) {    // 处理电机故障
                sys.abort = false;
                hal.stream.reset_read_buffer();
                system_raise_alarm(Alarm_MotorFault);
                grbl.report.feedback_message(Message_MotorFault);
            }

            // 只要 sys.rt_exec_alarm 不为0  killed 就为1
            if(!killed) // Tell driver/plugins about reset.
                hal.driver_reset();// 驱动或者插件的复位

            return !sys.abort; // Nothing else to do but exit.
        }
        
        // 目前只是实验，还有待验证。不要移动来打断上下文！跟控制台发送 0x19 (CMD_STOP) 有关
        // 有些函数还是预埋的空函数,还没有正式实现
        /*******************************跳过***********************************/
        if(rt_exec & EXEC_STOP) { // Experimental for now, must be verified. Do NOT move to interrupt context!

            sys.cancel = true;
            sys.step_control.flags = 0;
            sys.flags.feed_hold_pending = Off;
            sys.override_delay.flags = 0;
            if(sys.override.control.sync)
                sys.override.control = gc_state.modal.override_ctrl;

            gc_state.tool_change = false;

            // Tell driver/plugins about reset.
            hal.driver_reset();

            if(!sys.flags.keep_input && hal.stream.suspend_read && hal.stream.suspend_read(false))
                hal.stream.cancel_read_buffer(); // flush pending blocks (after M6)

            sys.flags.keep_input = Off;

            gc_init();
            plan_reset();
            if(sys.alarm_pending == Alarm_ProbeProtect) {
                st_go_idle();
                system_set_exec_alarm(sys.alarm_pending);
                sys.alarm_pending = Alarm_None;
            } else
                st_reset();
            sync_position();

            // Kill spindle and coolant. TODO: Check Mach3 behaviour?
            gc_spindle_off();
            gc_coolant((coolant_state_t){0});

            flush_override_buffers();
            if(!((state_get() == STATE_ALARM) && (sys.alarm == Alarm_LimitsEngaged || sys.alarm == Alarm_HomingRequired))) {
                state_set(hal.control.get_state().safety_door_ajar ? STATE_SAFETY_DOOR : STATE_IDLE);
                grbl.report.feedback_message(Message_Stop);
            }
        }
        /*******************************结束跳过***********************************/
        /*******************************信息的上报***********************************/
        // Execute and print status to output stream
        if (rt_exec & EXEC_STATUS_REPORT)
            report_realtime_status();

        if(rt_exec & EXEC_GCODE_REPORT)
            report_gcode_modes();

        if(rt_exec & EXEC_TLO_REPORT)
            report_tool_offsets();

        // Execute and print PID log to output stream
        if (rt_exec & EXEC_PID_REPORT)
            report_pid_log();
        /*******************************结束信息的上报***********************************/

        if(rt_exec & EXEC_RT_COMMAND)
            protocol_execute_rt_commands(0);//执行RT队列中的函数;这个函数形参没什么作用.

        rt_exec &= ~(EXEC_STOP|EXEC_STATUS_REPORT|EXEC_GCODE_REPORT|EXEC_PID_REPORT|EXEC_TLO_REPORT|EXEC_RT_COMMAND); // clear requests already processed

        // 这里不知道 sys.flags.feed_hold_pending 标志位的用处
        if(sys.flags.feed_hold_pending) {
            if(rt_exec & EXEC_CYCLE_START)
                sys.flags.feed_hold_pending = Off;
            else if(!sys.override.control.feed_hold_disable)
                rt_exec |= EXEC_FEED_HOLD;
        }

        // Let state machine handle any remaining requests\
        // 让状态机处理任何剩余的请求
        // 在这里 rt_exec 会写入到 sys_state 中
        // state_get() = sys_state = rt_exec = sys.rt_exec_state
        
        // 当屏蔽它的时候,输入"G1X100F1000"没有任何的反应
        if(rt_exec)
            state_update(rt_exec);
    }

    grbl.on_execute_realtime(state_get()); // 钩子

    // Execute overrides.
    // rt_exec = get_feed_override() 读取 feed 队列中的尾部的成员参数;当前不确定它是干嘛的
    if(!sys.override_delay.feedrate && (rt_exec = get_feed_override())) {

        override_t new_f_override = sys.override.feed_rate;
        override_t new_r_override = sys.override.rapid_rate;

        do {

            switch(rt_exec) {

                case CMD_OVERRIDE_FEED_RESET:
                    new_f_override = DEFAULT_FEED_OVERRIDE;
                    break;

                case CMD_OVERRIDE_FEED_COARSE_PLUS:
                    new_f_override += FEED_OVERRIDE_COARSE_INCREMENT;
                    break;

                case CMD_OVERRIDE_FEED_COARSE_MINUS:
                    new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT;
                    break;

                case CMD_OVERRIDE_FEED_FINE_PLUS:
                    new_f_override += FEED_OVERRIDE_FINE_INCREMENT;
                    break;

                case CMD_OVERRIDE_FEED_FINE_MINUS:
                    new_f_override -= FEED_OVERRIDE_FINE_INCREMENT;
                    break;

                case CMD_OVERRIDE_RAPID_RESET:
                    new_r_override = DEFAULT_RAPID_OVERRIDE;
                    break;

                case CMD_OVERRIDE_RAPID_MEDIUM:
                    new_r_override = RAPID_OVERRIDE_MEDIUM;
                    break;

                case CMD_OVERRIDE_RAPID_LOW:
                    new_r_override = RAPID_OVERRIDE_LOW;
                    break;
            }

            new_f_override = constrain(new_f_override, MIN_FEED_RATE_OVERRIDE, MAX_FEED_RATE_OVERRIDE);

        } while((rt_exec = get_feed_override()));//处理feed队列的全部剩余数据

        // 这里应该是覆盖快速运动和给进速度;先跳过
        plan_feed_override(new_f_override, new_r_override);
    }

    // 处理主轴相关的快速调整
    if(!sys.override_delay.spindle && (rt_exec = get_spindle_override())) {

        bool spindle_stop = false;
        spindle_ptrs_t *spindle = gc_spindle_get(-1)->hal;
        override_t last_s_override = spindle->param->override_pct;

        do {

            switch(rt_exec) {

                case CMD_OVERRIDE_SPINDLE_RESET:
                    last_s_override = DEFAULT_SPINDLE_RPM_OVERRIDE;
                    break;

                case CMD_OVERRIDE_SPINDLE_COARSE_PLUS:
                    last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT;
                    break;

                case CMD_OVERRIDE_SPINDLE_COARSE_MINUS:
                    last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT;
                    break;

                case CMD_OVERRIDE_SPINDLE_FINE_PLUS:
                    last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT;
                    break;

                case CMD_OVERRIDE_SPINDLE_FINE_MINUS:
                    last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT;
                    break;

                case CMD_OVERRIDE_SPINDLE_STOP:
                    spindle_stop = !spindle_stop;
                    break;

                default:
                    if(grbl.on_unknown_accessory_override)
                        grbl.on_unknown_accessory_override(rt_exec);
                    break;
            }

            last_s_override = constrain(last_s_override, MIN_SPINDLE_RPM_OVERRIDE, MAX_SPINDLE_RPM_OVERRIDE);

        } while((rt_exec = get_spindle_override()));

        spindle_set_override(spindle, last_s_override);

        if (spindle_stop && state_get() == STATE_HOLD && gc_spindle_get(-1)->state.on) {
            // Spindle stop override allowed only while in HOLD state.
            // NOTE: Report flag is set in spindle_set_state() when spindle stop is executed.
            if (!sys.override.spindle_stop.value)
                sys.override.spindle_stop.initiate = On;
            else if (sys.override.spindle_stop.enabled)
                sys.override.spindle_stop.restore = On;
        }
    }

    // 处理冷却剂相关的快速调整
    if(!sys.override_delay.coolant && (rt_exec = get_coolant_override())) {

        coolant_state_t coolant_state = gc_state.modal.coolant;

        do {

            switch(rt_exec) {

                case CMD_OVERRIDE_COOLANT_MIST_TOGGLE:
                    if(hal.coolant_cap.mist && ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD))))
                        coolant_state.mist = !coolant_state.mist;
                    break;

                case CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE:
                    if(hal.coolant_cap.flood && ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD))))
                        coolant_state.flood = !coolant_state.flood;
                    break;

                default:
                    if(grbl.on_unknown_accessory_override)
                        grbl.on_unknown_accessory_override(rt_exec);
                    break;
            }

        } while((rt_exec = get_coolant_override()));

      // NOTE: Since coolant state always performs a planner sync whenever it changes, the current
      // run state can be determined by checking the parser state.
        if(coolant_state.value != gc_state.modal.coolant.value) {
            gc_coolant(coolant_state); // Report flag set in gc_coolant().
            if(grbl.on_override_changed)
                grbl.on_override_changed(OverrideChanged_CoolantState);
        }
    }

    // End execute overrides.

    // Reload step segment buffer
    if (state_get() & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG))
        st_prep_buffer(); // 这里在读取运动控制块中的数据做加减速度规划

    return !ABORTED;
}

// Handles grblHAL system suspend procedures, such as feed hold, safety door, and parking motion.
// The system will enter this loop, create local variables for suspend tasks, and return to
// whatever function that invoked the suspend, such that grblHAL resumes normal operation.
// This function is written in a way to promote custom parking motions. Simply use this as a
// template.
// state - 系统状态
// 这个函数提供系统挂起功能
static void protocol_exec_rt_suspend (sys_state_t state)
{
    if((sys.blocking_event = state == STATE_SLEEP)) {
        *line = '\0';
        char_counter = 0;
        hal.stream.reset_read_buffer();
    }

    while(sys.suspend) {

        if(sys.abort)//终止?
            return;

        if(sys.blocking_event)// 阻塞标志为1 读取控制台的字符串到 line 数组中
            protocol_poll_cmd();

        // Handle spindle overrides during suspend
        // 在挂起期间处理主轴覆盖; 这里先跳过
        state_suspend_manager();

        // If door closed keep issuing door closed requests until resumed
        // 如果当前安全门被触发，那持续检测安全门，直到限位信息被解除，才将 sys.rt_exec_state 状态设置为 EXEC_DOOR_CLOSED
        if(state_get() == STATE_SAFETY_DOOR && !hal.control.get_state().safety_door_ajar)
            system_set_exec_state_flag(EXEC_DOOR_CLOSED);

        // Check for sleep conditions and execute auto-park, if timeout duration elapses.
        // Sleep is valid for both hold and door states, if the spindle or coolant are on or
        // set to be re-enabled.
        // settings.flags.sleep_enable 是 $62
        if(settings.flags.sleep_enable)
            sleep_check();

        protocol_exec_rt_system();
    }
}

// Pick off (drop) real-time command characters from input stream.
// These characters are not passed into the main buffer,
// but rather sets system state flag bits for later execution by protocol_exec_rt_system().
// Called from input stream interrupt handler.
// 处理控制台输入的 RT 指令;比如 ? ! ~ 和 0x03,0x19等特殊字符的处理
// 这里很多指令的相应是通过标记 sys.rt_exec_state 的对应位;并没有立刻执行
// 返回1 表示成功从控制台取出实时指令
ISR_CODE bool ISR_FUNC(protocol_enqueue_realtime_command)(char c)
{
    static bool esc = false;

    bool drop = false;

    // 1. Process characters in the ranges 0x - 1x and 8x-Ax
    // Characters with functions assigned are always acted upon even when the input stream
    // is redirected to a non-interactive stream such as from a SD card.

    switch ((unsigned char)c) {

        case '\n':
        case '\r':
            break;

        case '$':
            if(char_counter == 0)
                // 跟 $39 有关
                // 比如 $H 的 H 需要用 0x48 表示 keep_rt_commands = 1的时候 H 用 C8(0x48 | 0x80) 表示
                // settings.flags.legacy_rt_commands 为 1（启用传统命令），则 keep_rt_commands 会被设置为 0，停止实时命令的处理。
                // 如果 legacy_rt_commands 被禁用，则启用实时命令的处理（即 keep_rt_commands = 1）
                keep_rt_commands = !settings.flags.legacy_rt_commands;
            break;

        case CMD_STOP://0x19
            // 设置 sys.rt_exec_state 的 EXEC_STOP 位
            system_set_exec_state_flag(EXEC_STOP);
            char_counter = 0;                       // 清空指令长度
            hal.stream.cancel_read_buffer();        // 取消串口缓存区中的指令,这个需要串口插件支持
            drop = true;
            break;

        case CMD_RESET: // Call motion control reset routine.
            if(!hal.control.get_state().e_stop)
                mc_reset(); // 这里先不管 ISR_CODE void ISR_FUNC(mc_reset)(void) 跳过
            drop = true;
            break;

#if COMPATIBILITY_LEVEL == 0
        case CMD_EXIT: // Call motion control reset routine.
            mc_reset();
            sys.flags.exit = On;
            drop = true;
            break;
#endif

        case CMD_STATUS_REPORT_ALL: // Add all statuses to report
            {
                report_tracking_flags_t report;

                report.value = (uint32_t)Report_All;
                report.tool_offset = sys.report.tool_offset;
                report.m66result = sys.var5399 > -2;

                system_add_rt_report((report_tracking_t)report.value); // 先跳过
            }
            system_set_exec_state_flag(EXEC_STATUS_REPORT);
            drop = true;
            break;

        case CMD_STATUS_REPORT:
        case 0x05:
            if(!sys.flags.auto_reporting)
                system_set_exec_state_flag(EXEC_STATUS_REPORT);
            drop = true;
            break;

        case CMD_CYCLE_START:
            system_set_exec_state_flag(EXEC_CYCLE_START);
            // Cancel any pending tool change
            gc_state.tool_change = false;
            drop = true;
            break;

        case CMD_FEED_HOLD:
            system_set_exec_state_flag(EXEC_FEED_HOLD);
            drop = true;
            break;

        case CMD_SAFETY_DOOR:
            if(state_get() != STATE_SAFETY_DOOR) {
                system_set_exec_state_flag(EXEC_SAFETY_DOOR);
                drop = true;
            }
            break;

        case CMD_JOG_CANCEL: // 取消JOG
            char_counter = 0;
            drop = true;
            hal.stream.cancel_read_buffer(); // 取消串口缓存区中的指令,这个需要串口插件支持
#ifdef KINEMATICS_API // needed when kinematics algorithm segments long jog distances (as it blocks reading from input stream)
            if (state_get() & STATE_JOG) // Block all other states from invoking motion cancel.
                system_set_exec_state_flag(EXEC_MOTION_CANCEL);
#endif
            if(grbl.on_jog_cancel)
                grbl.on_jog_cancel(state_get());
            break;

        case CMD_GCODE_REPORT:
            system_set_exec_state_flag(EXEC_GCODE_REPORT);
            drop = true;
            break;

        case CMD_PROBE_CONNECTED_TOGGLE:
            if(hal.probe.connected_toggle)
                hal.probe.connected_toggle();
            break;

        case CMD_OPTIONAL_STOP_TOGGLE:
            if(!hal.signals_cap.stop_disable) // Not available as realtime command if HAL supports physical switch
                sys.flags.optional_stop_disable = !sys.flags.optional_stop_disable;
            break;

        case CMD_SINGLE_BLOCK_TOGGLE:
            if(!hal.signals_cap.single_block) // Not available as realtime command if HAL supports physical switch
                sys.flags.single_block = !sys.flags.single_block;
            break;

        case CMD_PID_REPORT:
            system_set_exec_state_flag(EXEC_PID_REPORT);
            drop = true;
            break;

        case CMD_MPG_MODE_TOGGLE:           // Switch off MPG mode
            if((drop = hal.stream.type == StreamType_MPG))
                protocol_enqueue_foreground_task(stream_mpg_set_mode, NULL);
            break;

        case CMD_AUTO_REPORTING_TOGGLE:
            if((drop = settings.report_interval != 0))
                sys.flags.auto_reporting = !sys.flags.auto_reporting;
            break;

        case CMD_OVERRIDE_FEED_RESET:
        case CMD_OVERRIDE_FEED_COARSE_PLUS:
        case CMD_OVERRIDE_FEED_COARSE_MINUS:
        case CMD_OVERRIDE_FEED_FINE_PLUS:
        case CMD_OVERRIDE_FEED_FINE_MINUS:
        case CMD_OVERRIDE_RAPID_RESET:
        case CMD_OVERRIDE_RAPID_MEDIUM:
        case CMD_OVERRIDE_RAPID_LOW:
            drop = true;
            enqueue_feed_override(c);
            break;

        case CMD_OVERRIDE_SPINDLE_RESET:
        case CMD_OVERRIDE_SPINDLE_COARSE_PLUS:
        case CMD_OVERRIDE_SPINDLE_COARSE_MINUS:
        case CMD_OVERRIDE_SPINDLE_FINE_PLUS:
        case CMD_OVERRIDE_SPINDLE_FINE_MINUS:
        case CMD_OVERRIDE_SPINDLE_STOP:
            drop = true;
            enqueue_spindle_override((uint8_t)c);
            break;

        case CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE:
        case CMD_OVERRIDE_COOLANT_MIST_TOGGLE:
        case CMD_OVERRIDE_FAN0_TOGGLE:
            drop = true;
            enqueue_coolant_override((uint8_t)c);
            break;

        case CMD_REBOOT:
            if(esc && hal.reboot)
                hal.reboot(); // Force MCU reboot. This call should never return.
            break;

        default:
            if((c < ' ' && c != ASCII_BS) || (c > ASCII_DEL && c <= 0xBF))
                // 钩子函数,处理未知的实时指令
                drop = grbl.on_unknown_realtime_cmd == NULL || grbl.on_unknown_realtime_cmd(c);
            break;
    }

    // 2. Process printable ASCII characters and top-bit set characters
    //    If legacy realtime commands are disabled they are returned to the input stream
    //    when appearing in settings ($ commands) or comments

    if(!drop) switch ((unsigned char)c) {
        case CMD_STATUS_REPORT_LEGACY:
            if(!keep_rt_commands || settings.flags.legacy_rt_commands) {
                system_set_exec_state_flag(EXEC_STATUS_REPORT);
                drop = true;
            }
            break;

        case CMD_CYCLE_START_LEGACY:
            if(!keep_rt_commands || settings.flags.legacy_rt_commands) {
                system_set_exec_state_flag(EXEC_CYCLE_START);
                // Cancel any pending tool change
                gc_state.tool_change = false;
                drop = true;
            }
            break;

        case CMD_FEED_HOLD_LEGACY: // ! 暂停指令
            if(!keep_rt_commands || settings.flags.legacy_rt_commands) {
                system_set_exec_state_flag(EXEC_FEED_HOLD);
                drop = true;
            }
            break;

        default: // Drop top bit set characters
            drop = !(keep_rt_commands || (unsigned char)c < 0x7F);
            break;
    }

    esc = c == ASCII_ESC;

    return drop;
}

// 这个变量跟 protocol_execute_rt_commands 有关;暂时不知道它干嘛的
static const uint32_t dummy_data = 0;


/*! \brief Enqueue a function to be called once by the foreground process.
\param fn pointer to a \a foreground_task_ptr type of function.
\param data pointer to data to be passed to the callee.
\returns true if successful, false otherwise.
*/
// 注册一个函数到 realtime_queue 中,并设置 sys.rt_exec_state 为 EXEC_RT_COMMAND
ISR_CODE bool ISR_FUNC(protocol_enqueue_foreground_task)(fg_task_ptr fn, void *data)
{
    bool ok;
    uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1);    // Get next head pointer

    if((ok = bptr != realtime_queue.tail)) {                    // If not buffer full
        realtime_queue.task[realtime_queue.head].data = data;
        realtime_queue.task[realtime_queue.head].task = fn;       // add function pointer to buffer,
        realtime_queue.head = bptr;                             // update pointer and
        system_set_exec_state_flag(EXEC_RT_COMMAND);            // flag it for execute
    }

    return ok;
}

/*! \brief Enqueue a function to be called once by the foreground process.
\param fn pointer to a \a on_execute_realtime_ptr type of function.
\returns true if successful, false otherwise.
__NOTE:__ Deprecated, use protocol_enqueue_foreground_task instead.
*/
ISR_CODE bool ISR_FUNC(protocol_enqueue_rt_command)(on_execute_realtime_ptr fn)
{
    return protocol_enqueue_foreground_task(fn, (void *)&dummy_data);
}

// Execute enqueued functions.
// 执行RT队列中的函数;形参没什么作用
static void protocol_execute_rt_commands (sys_state_t state)
{
    /* 从这可以看出来这是一个环形缓冲区,头不等于尾的时候条件成立 */
    while(realtime_queue.tail != realtime_queue.head) {
        uint_fast8_t bptr = realtime_queue.tail;
        if(realtime_queue.task[bptr].task.fn) {// 任务函数指针不为空
            if(realtime_queue.task[bptr].data == (void *)&dummy_data) {// 这里区分用哪个函数原型;这里实现的是一个类似函数重载的功能
                on_execute_realtime_ptr call = realtime_queue.task[bptr].task.fn_deprecated;
                realtime_queue.task[bptr].task.fn_deprecated = NULL;
                call(state_get());// 运行realtime_queue.task[bptr].task.fn_deprecated指针指向的函数;并且释放这个指针
            } else {
                foreground_task_ptr call = realtime_queue.task[bptr].task.fn;
                realtime_queue.task[bptr].task.fn = NULL;
                call(realtime_queue.task[bptr].data);
            }
        }
        // 尾指针向前递增,并做最大值限制 这意味着这些RT函数只会执行一遍
        realtime_queue.tail = (bptr + 1) & (RT_QUEUE_SIZE - 1);
    }

    if(!sys.driver_started)// 驱动程序准备情况;这里需要有有一些断言的操作
        while(true);
}

void protocol_execute_noop (sys_state_t state)
{
    (void)state;
}
